#ifndef __SE_CACHE_MANAGER_HPP__
#define __SE_CACHE_MANAGER_HPP__

#include "Singleton.hpp"
#include "MutexLock.hpp"

#include "json.hpp"

#include <string>
#include <vector>
#include <map>

namespace se {

class LRUCache;
class CacheManager : Singleton<CacheManager>
{
    using json = nlohmann::json;
    using Key = std::string;
    using CacheList = std::vector<LRUCache>;  //每个Cache由两个LRUCache对象组成，其中一个是平时提供服务的，一个是更新时提供服务的
    using Pointer = CacheList::iterator;
    using ThreadMap = std::map<unsigned long, Pointer>;  //线程ID和LRUCache的映射
public:
    /**
     * @brief 构造函数
     */
    CacheManager();

    /**
     * @brief 析构时把缓存内容保存到磁盘
     */
    ~CacheManager();

    /**
     * @brief 对外提供的用于查找的接口
     * @param in key 查找关键字 
     * @return const json & 查找成功时返回结果值，没找到返回空的json对象
     */
    std::shared_ptr<nlohmann::json> find(const Key & key);

    /**
     * @brief 在cache中插入记录
     * @param in record 待插入的数据
     */
    void insertToCache(const std::pair<Key, json> & record);

    /**
     * @brief 更新并同步各个Cache里的热数据
     */
    void updateCache();

    /**
     * @brief 将Cache中的内容写到文件中备份
     */
    void saveCacheToFile();
private:
    /**
     * @brief 初始化Cache，从文件中读取记录到LRUCache中
     * @param in fileName 文件名
     */
    void init();
    
    /**
     * @brief 拷贝Cache中的内容，到备用Cache，为切换Cache做准备，实现无缝更新
     */
    void copyCache();

    /**
     * @brief 更换对外提供查询服务的Cache，用于无缝更新
     */
    void switchCache();

    /**
     * @brief 获取Cache资源
     * @param in processId 线程Id
     * @return LRUCache 与线程一一对应的LRUCache
     */
    LRUCache & getCache(unsigned long processId);
private:
    CacheList _caches;  //每个线程对应两个Cache，偶数号下标是主Cache，奇数号是对应的辅助更新Cache
    ThreadMap _threadMap;  //线程ID对应Cache的映射
    std::vector<std::pair<bool, CacheList::iterator>> _cacheIsUsed;  //记录Cache是否被占用，给线程分配Cache时使用
    int _switchCache;  //标识正在工作的是主Cache还是副Cache
    MutexLock _switchMutex;  //切换线程时的锁
    MutexLock _copyMutex;  //复制时的锁，如果正在复制，禁止插入
    std::string _LRUCachePath;  //缓存的保存路径
};

}  // namespace se

#endif
